from logging import raiseExceptions
import math
import sys
from ast import LShift, expr_context
from asyncio.constants import SENDFILE_FALLBACK_READBUFFER_SIZE
from audioop import bias
from copyreg import constructor
from email.errors import CloseBoundaryNotFoundDefect
from ntpath import realpath
from os import EX_CANTCREAT
from re import L
from tkinter import E
# import src.gmid
import numpy as np
import pytest
# from src.gmid.gmidinit.LupMos import lookup
from lut.lookuptable.MOSinfo import *
# from gmid.gmidinit.MOSinfo import LUT_DB
# from gmid.gmidinit.MOSinfo import *
# from wyf.gmid.gmidinit.MOSinfo import *

# from pyted import *
# from src.gmid.gmidinit.Searchpar import MOS


lut = LUT_DB(method="TD")
def lookup(VGS, VBS, VDS, L, method="comb", model="pch", outpar="GMOVERID"):
    if L==0.06 or L==0.18 or L==0.04:
        L=L+0.001
        
    if model == "pch":
        value = lut.lookup(
                    method="comb", model="pch", outpar=outpar, VGS=-VGS, VBS=-VBS, VDS=-VDS, L=L, check=False
                )
    else:
        value = lut.lookup(
                    method="comb", model="nch", outpar=outpar, VGS=VGS, VBS=VBS, VDS=VDS, L=L, check=False
                )
    
    if len(value)==1:
        cell = value[0]
    else:
        cell = value
        raise Exception("此处代码需要更改")
    if cell<0:
        debug("*********此处需注意正负，输出已取绝对值*********", outpar)
    return abs(cell)


class MOSpara:
    def __init__(self):
        self.l = 0
        self.w = 0
        self.m = 0
        self.gm = 0
        self.id = 0
        self.vds = 0
        self.vbs = 0
        self.gds = 0
        self.vgs = 0
        self.vdsat = 0
        self.gdsOverId = 0
        self.gmid = 0
        self.idOverW = 0
        self.selfGain = 0
        self.pai = math.pi
        self.k = 1.38e-23  # 玻尔兹曼常数
        self.T = 273  # 开尔文温度
        self.csg = 0
        self.cgs = 0
        self.cgd = 0

    def parallel(self, *args):
        if len(args) == 1:
            raise Exception("The number of input parameters must be greater than 1")
        for i in range(0, len(args)):
            if i == 0:
                res = args[0]
            else:
                res = (res * args[i]) / (res + args[i])
        return res


class ful_dif_amp:
    def __init__(self, vdd: float, vcm, Cload: float, Iref, multi=4, **spec) -> None:
        for k, v in spec.items():
            kupper = k.upper()  # 大写统一
            if kupper == "GAIN":
                gain = v
            elif kupper == "SR":
                SR = v
            elif kupper == "GBW":
                GBW = v
            elif kupper == "ICMR_MAX":
                ICMR_max = v
            elif kupper == "ICMR_MIN":
                ICMR_min = v
            elif kupper == "NOISE":  # 量纲：V/sqr(Hz)
                noise = v
            else:
                raise Exception("params格式设置错误，存在未知参数:", k)
        self.vdd = vdd
        self.pdk = os.environ.get("PDK") or "t65"
        # self.pdk = "s180bcd"
        # self.lmin = circuit.get_pdk().config["size"]["lmin"] * 1e-3
        if self.pdk in ["t40"]:
            self.lmin = 0.04
            ICMR_min =-0.26
            ICMR_max =0.6
        elif self.pdk in ["s180mm", "s180bcd", "sharp180", "t180"]:
            self.lmin = 0.18
            ICMR_min =-0.28
            ICMR_max =0.9
        elif self.pdk in ["t65"]:
            self.lmin = 0.06
            ICMR_min =-0.28
            ICMR_max =0.6
        debug(self.pdk)
        self.vcm_1st = vcm
        self.bias_multi = multi
        self.Iref = Iref

        

        """sizing start"""
        M1 = MOSpara()
        M2 = MOSpara()
        M3 = MOSpara()
        
        # x1 = lookup(
        #             method="comb", model="nch",
        #             outpar="ID",
        #             VGS=0.67,
        #             VBS=-0.18,
        #             VDS=1,
        #             L=0.181,
        #         )
        # debug("在这儿输出：",x1)
        # for i in [0.4, 0.5, 0.6, 0.7, 0.8]:
        #     debug(
        #         1/lookup(
        #             method="comb", model="pch", outpar="1", VGS=i, VBS=-0, VDS=0.6, L=1
        #         )
        #     )
        # cgs1 = lookup(
        #     method="comb", model="pch", outpar="CGS", VGS=0.72, VBS=-0.18, VDS=0.6, L=0.27
        # )
        # cgs2 = lookup(
        #     method="comb", model="pch", outpar="CGS", VGS=0.72, VBS=-0.33, VDS=0.6, L=0.27
        # )
        # ii1 = lookup(
        #     method="comb", model="pch", outpar="ID", VGS=0.72, VBS=-0.18, VDS=0.6, L=0.27
        # )
        # i2 = lookup(
        #     method="comb", model="pch", outpar="ID", VGS=0.72, VBS=-0.33, VDS=0.6, L=0.27
        # )
        # debug(ii1)
        # w1 = (100e-5)/ii1
        # w2 = (100e-5)/i2
        # debug(
        #     w1*cgs1, w2*cgs2
        # )
        
        if self.pdk in ["t65"]:
            GBW=GBW+3e6
            gain=gain+4
        elif self.pdk in ["t40"]:
            gain=gain+0.3
            
        Llist = np.arange(3 * self.lmin, 20 * self.lmin, self.lmin)
        flag0 = 1
        for l in Llist:
            M1.l = round(l, 2)
            # GBWcorrect = GBW * 1.2
            # debug(GBWcorrect, SR)
            M1.gmid = 4 * math.pi * GBW / SR
            M1.gmid = 12
            if self.pdk in ["t65"]:
                M1.gmid=15
            elif self.pdk in ["t40"]:
                M1.gmid=15.5
            
            global P_vds, N_vds
            P_vds = 0
            for v1 in np.arange(0.1, 0.4, 0.01):
                for v2 in np.arange(0.3, self.vdd / 2 * 1.5, 0.01):
                    M1.vds = self.vdd - 2 * v1
                    # debug(M1.l, v2, v1, M1.vds)
                    if M1.vds > 1:
                        M1.vds = 1
                    # debug(v2, -v1, M1.vds, M1.l)
                    gmid1 =  lookup(
                          method="comb", model="pch", outpar="GMOVERID", VGS=v2, VBS=-v1, VDS=M1.vds, L=M1.l
                    )
                    # debug("就是这里：", gmid1, v2)
                    if M1.gmid - 0.5 < gmid1 and gmid1 < M1.gmid + 0.5:
                        # if M1.gmid < gmid1:
                        M1.vgs = v2
                        M1.gmid = gmid1
                        break
                # debug(M1.vgs)
                if M1.vgs == 0:
                    raise Exception("error")
                P_vdsat = self.vdd - (ICMR_max + M1.vgs)
                P_vdsat = 0.15
                if self.pdk in ["s180mm", "s180bcd", "sharp180"]:
                    P_vdsat = 0.22
                # debug(
                #     M1.vgs,
                #     P_vdsat,
                #     v1,
                #     M1.vds,
                #     v2,
                #      lookup(  method="comb", model="pch", outpar="VT", VGS=v2, VBS=-v1, VDS=M1.vds, L=M1.l),
                # )
                if P_vdsat - 0.01 < v1 and v1 < P_vdsat + 0.01:
                    P_vds = v1
                    break
            if P_vds == 0:
                raise Exception("error")
            M1.vdsat =  lookup(
                  method="comb", model="pch", outpar="VDSAT", VGS=M1.vgs, VBS=-P_vds, VDS=M1.vds, L=M1.l
            )
            N_vds = ICMR_min + M1.vgs - M1.vdsat
            N_vds = 0.18
            if self.pdk in ["t40", "t65"]:
               N_vds = 0.15 
            
            debug("par1 is:", M1.vgs, P_vds, N_vds)
            self.Nbias = self.NbiasSizing(Iref, N_vds, 2 * l)
            self.Pbias = self.PbiasSizing(Iref, P_vds, 2 * l)
            gain_1st = 10 ** (gain * 4 / 5 / 20)
            gain_2nd = 10 ** (gain * 1 / 5 / 20)
            # if GBW > 200e6:
            #     gain_1st = 10**(gain * 4/5 /20)
            #     gain_2nd = 10**(gain * 1/5 /20)
            # else:
            #     gain_1st = 10**(gain * 3/4 /20)
            #     gain_2nd = 10**(gain * 1/4 /20)
            noise_square = noise**2
            Cc = Cload * 1 / 6
            
            M1.gm = GBW * Cc * 4 * math.pi
            M1.id = M1.gm/M1.gmid
            
            self.Cc_cascode = Cc
            if self.pdk in ["sharp180",]:
                self.Cc_cascode = Cc*1
            elif self.pdk in ["s180bcd","s180mm"]:#原本修正系数为2
                self.Cc_cascode = Cc*1
                # self.Cc_cascode = Cc*3
            elif self.pdk in ["t180"]:  
                self.Cc_cascode = Cc*1
                # self.Cc_cascode = Cc*2.5
            elif self.pdk in ["t40"]:  
                self.Cc_cascode = Cc*1
            elif self.pdk in ["t65"]:  
                self.Cc_cascode = Cc*1.05
            
            global first_multi
            first_multi = math.ceil(M1.id/2 / (Iref / self.bias_multi))
            first_multi = first_multi*2
            M1.id = first_multi * (Iref / self.bias_multi)
            M1.gm = M1.gmid * M1.id
            # debug(M1.id, M1.gm)
            M1.w = M1.id / (
                 lookup(  method="comb", model="pch", outpar="ID", VGS=M1.vgs, VBS=-P_vds, VDS=M1.vds, L=M1.l)
                / 5
            )
            M1.gds = (
                 lookup(
                      method="comb", model="pch", outpar="GDS", VGS=M1.vgs, VBS=-P_vds, VDS=M1.vds, L=M1.l
                )
                / 5
                * M1.w
            )
            M1.cgs = (
                 lookup(
                      method="comb", model="pch", outpar="CGS", VGS=M1.vgs, VBS=-P_vds, VDS=M1.vds, L=M1.l
                )
                / 5
                * M1.w
            )
            # debug(M1.cgs)
            boostor_GBW = GBW * 0.05
            # if self.pdk in ["s180mm", "s180bcd", "sharp180", "t180"]:
            #     boostor_GBW = GBW * 0.1
            # gmid2List = np.arange(8, 25, 1)#这个值小噪声低，次极点高，这个值大增益高
            vgs2List = np.arange(
                self.vdd - 1.2 * P_vds - 1.2 * P_Nvds, self.vdd / 2+0.1, -0.01
            )
            if self.vdd - 1.2 * P_vds - 1.2 * P_Nvds > 1:
                vgs2List = np.arange(1, self.vdd / 2, -0.01)
            # debug(vgs2List)
            M2.id = M1.id
            M2.vds = self.vdd / 2 - P_vds
            M2.vbs = P_vds
            M2.l = M1.l
            flag1 = 1

            for v3 in vgs2List:
                v3 = v3 - 0.05
                M2.idOverW = (
                     lookup(
                          method="comb", model="pch", outpar="ID", VGS=v3, VBS=-M2.vbs, VDS=M2.vds, L=M2.l
                    )
                    / 5
                )
                M2.w = M1.id / M2.idOverW
                M2.cgs = (
                     lookup(
                          method="comb", model="pch", outpar="CGS", VGS=v3, VBS=-M2.vbs, VDS=M2.vds, L=M2.l
                    )
                    / 5
                    * M2.w
                )
                M2.gm = (
                     lookup(
                          method="comb", model="pch", outpar="GM", VGS=v3, VBS=-M2.vbs, VDS=M2.vds, L=M2.l
                    )
                    / 5
                    * M2.w
                )
                M2.gds = (
                     lookup(
                          method="comb", model="pch", outpar="GDS", VGS=v3, VBS=-M2.vbs, VDS=M2.vds, L=M2.l
                    )
                    / 5
                    * M2.w
                )
                self.GBN_Cc = self.NgainboostorSizing(boostor_GBW, M2.cgs)
                self.GBP_Cc = self.PgainboostorSizing(boostor_GBW, M2.cgs)
                gain1calcu = self.gainCalcu(
                    1 / M1.gds, M1.gm, 1 / M2.gds, M2.gm, 1 / M2.gds, M2.gm, first_multi
                )
                if self.pdk in ["t40"]:
                    gain1calcu = gain1calcu*0.9
                noiseCalcu = self.noiseCalcu(
                    1 / M1.gds, M1.gm, 1 / M2.gds, M2.gm, 1 / M2.gds, M2.gm, first_multi
                )
                # debug(
                #      lookup(
                         
                #         method="comb", 
                #         model="pch",
                #         outpar="SELF_GAIN",
                #         VGS=v3,
                #         VBS=-M2.vbs,
                #         VDS=M2.vds,
                #         L=M2.l,
                #     )
                # )
                debug("噪声：", noiseCalcu, noise_square)
                debug("增益：", gain1calcu, gain_1st)
                if noiseCalcu < noise_square and gain1calcu > gain_1st:
                    M2.vgs = v3
                    flag1 = 0
                    break
            # debug(
            #     "***********", gain1calcu, gain_1st, M1.l, M1.gds, M2.gds, Ngds1, Pgds1
            # )
            if gain1calcu > gain_1st:
                flag0 = 0
                break
        M2.selfGain =  lookup(
              method="comb", model="pch", outpar="SELF_GAIN", VGS=M2.vgs, VBS=-M2.vbs, VDS=M2.vds, L=M2.l
        )
        
        if flag1:
            raise Exception("噪声不能达到要求！")
        if flag0:
            raise Exception("增益不能达到要求！")

        M3.vbs = N_vds
        M3.vds = self.vdd / 2 - N_vds
        vgs3List = np.arange(self.vdd - 1.2 * N_vds - 1.2 * N_Pvds, self.vdd / 2, -0.01)
        
        if self.vdd - 1.2 * N_vds - 1.2 * N_Pvds > 1.1:
            vgs3List = np.arange(1.1, self.vdd / 2, -0.01)
        Llist1 = np.arange(M2.l, 20 * self.lmin, self.lmin)

        for l1 in Llist1:
            for v4 in vgs3List:
                v4 = v4 - 0.05
                M3.idOverW = (
                    lookup( method="comb", model="nch", outpar="ID", VGS=v4, VBS=-M3.vbs, VDS=M3.vds, L=l1)
                    / 5
                )
                # debug(M3.idOverW, M1.id)
                M3.w = M1.id / M3.idOverW
                M3.gm = (
                    lookup( method="comb", model="nch", outpar="GM", VGS=v4, VBS=-M3.vbs, VDS=M3.vds, L=l1)
                    / 5
                    * M3.w
                )
                M3.selfGain = lookup(
                     method="comb", model="nch", outpar="SELF_GAIN", VGS=v4, VBS=-M3.vbs, VDS=M3.vds, L=l1
                )
                # debug(M2.gm , M3.gm, l1)
                # debug(M2.vgs, v4)
                debug("*****Here is M3 calcu", M2.selfGain, M3.selfGain, M3.vgs)
                GainReq = M2.selfGain
                if self.pdk in ["t40"]:
                   GainReq = 0.85*M2.selfGain 
                elif self.pdk in ["t65"]:
                    GainReq = 0.9*M2.selfGain
                if M3.selfGain > GainReq:
                    M3.vgs = v4
                    M3.l = l1
                    break
            if M3.l != 0:
                break
        M3.l = round(M3.l, 2)
        if M3.vgs == 0:
            raise Exception("error!")
            # M3.gds = lookup( method="comb", model="nch", "GDS", VGS = M3.vgs, VBS = -M3.vbs, VDS = M3.vds, L = l1)/5*M3.w
            # debug(M3.gds, M2.gds)
            # if M3.gds<M2.gds:
            #     M3.l = l1
            #     break
        # if M3.l == 0:
        #     raise Exception("error!")
        # debug(M2.vgs, M3.vgs)
        divide = 1
        # if self.pdk in ["s180bcd", "sharp180"]:
        #     divide = 2.5
        debug("M3.vgs is ", M3.vgs, M1.vgs)
        M1.m = math.ceil(M1.w / 4 / (self.P_unitm / divide))
        M1.m = M1.m * 4
        M1.w = round(M1.w / M1.m, 2)
        M2.m = math.ceil(M2.w/2 / (self.P_unitm / divide))
        M2.m = M2.m*2
        if M2.m == 0:
            M2.m = 1
        M2.w = round(M2.w / M2.m, 2)

        if M2.w < 1.56 and self.pdk in ["s180bcd", "sharp180", "s180mm", "t180"]:
            M2.w = round(M2.w*2, 2)
            M2.m = int(M2.m/2)
        M3.m = math.ceil(M3.w/2 / (self.P_unitm / divide))
        M3.m=M3.m*2

        if M3.m == 0:
            M3.m = 1
        M3.w = round(M3.w / M3.m, 2)
        if M3.w < 1.56 and self.pdk in ["s180bcd", "sharp180", "s180mm", "t180"]:
            M3.w = round(M3.w*2, 2)
            M3.m = int(M3.m/2)
        if M3.w < 0.7 and self.pdk in ["t65"]:
            M3.w = round(M3.w*2, 2)
            M3.m = int(M3.m/2)
        if M3.w < 0.53 and self.pdk in ["t40"]:
            M3.w = round(M3.w*2, 2)
            M3.m = int(M3.m/2)
            
        self.firstStageAmp = [
            [M1.w * 1e-6, M3.w * 1e-6, M2.w * 1e-6],
            [M1.l * 1e-6, M3.l * 1e-6, M2.l * 1e-6],
            [M1.m, M3.m, M2.m],
            [first_multi],
            [round(first_multi)],
        ]


        debug("N cascode is :", M2.vgs, M2.selfGain, vgs2List)
        

        """第二级放大器"""
        M4 = MOSpara()
        second_multi = first_multi * 3
        M4.id = M1.id * 3
        if self.pdk in ["s180mm", "sharp180", "t180"]:
            second_multi = first_multi * 3
            M4.id = M1.id * 3
        elif self.pdk in ["s180bcd"]:
            second_multi = first_multi * 3
            M4.id = M1.id * 3
        M4.vbs = N_vds
        M4.vds = self.vdd - N_vds - P_vds - 0.2
        if M4.vds > 1:
            M4.vds = 1
        C_cmfb1 = 1e-13
        C_cmfb2 = 1e-13
        if GBW > 200e6:
            C_cmfb1 = 3e-13
            C_cmfb2 = 3e-13
        flag2 = 1
        for l2 in np.arange(self.lmin, 20 * self.lmin, self.lmin):
            debug(self.vdd / 2 - N_vds - 0.05, -M4.vbs, M4.vds, l2)
            M4.idOverW = (
                 lookup(
                    method="comb", model="nch",
                    outpar="ID",
                    VGS=self.vdd / 2 - N_vds - 0.05,
                    VBS=-M4.vbs,
                    VDS=M4.vds,
                    L=l2,
                )
                / 5
            )
            M4.w = M4.id / M4.idOverW
            
            M4.gm = (
                lookup(
                     
                    method="comb", model="nch",
                    outpar="GM",
                    VGS=self.vdd / 2 - N_vds - 0.05,
                    VBS=-M4.vbs,
                    VDS=M4.vds,
                    L=l2,
                )
                / 5
                * M4.w
            )
            # debug(M4.gm)
            M4.gds = (
                lookup(
                     
                    method="comb", model="nch",
                    outpar="GDS",
                    VGS=self.vdd / 2 - N_vds - 0.05,
                    VBS=-M4.vbs,
                    VDS=M4.vds,
                    L=l2,
                )
                / 5
                * M4.w
            )
            gain2calcu = M4.gm / (M4.gds + Pgds1 * second_multi / self.bias_multi)
            debug(
                gain2calcu,
                M4.gm,
                1 / M4.gds,
                1 / (Pgds1 * second_multi / self.bias_multi),
            )
            M4.cgs = (
                lookup(
                     
                    method="comb", model="nch",
                    outpar="CGS",
                    VGS=self.vdd / 2 - N_vds - 0.05,
                    VBS=-M4.vbs,
                    VDS=M4.vds,
                    L=l2,
                )
                / 5
                * M4.w
            )
            M4.cgd = (
                lookup(
                     
                    method="comb", model="nch",
                    outpar="CGD",
                    VGS=self.vdd / 2 - N_vds - 0.05,
                    VBS=-M4.vbs,
                    VDS=M4.vds,
                    L=l2,
                )
                / 5
                * M4.w
            )
            if self.pdk in ["s180mm", "s180bcd", "sharp180", "t180"]:
                C_cmfb1 = 8e-13
                C_cmfb2 = 8e-13
            C1 = M4.cgs + M4.cgd * gain2calcu + C_cmfb1
            C2 = Cload + C_cmfb2
            C3 = M2.cgs
            Cmtp = C1 * C2 * C3
            Gmmtp = M2.gm * M4.gm * (1 / self._PGB_Rin)
            debug("M4 par is", self.vdd / 2 - N_vds - 0.05, -M4.vbs, M4.vds, M4.l, M4.w, N_vds)
            debug("Cpar:", M4.cgs, M4.cgd, gain2calcu, C_cmfb1)
            debug(C1, C2, C3)
            debug(M2.gm, M4.gm, 1 / self._PGB_Rin)
            # debug(1/self._PGB_Rin, Pgm2)
            fndCalcu = (2 * Gmmtp / Cmtp) ** (1 / 3) / (2 * math.pi)
            debug("计算的次极点为：",fndCalcu)
            
            
            debug("***GBW par is :", M1.gm, M1.id, M1.gmid, Cc, GBW)

            # if gain > 70:
            #     gainCor = 0.95*gain_2nd
            # else:
            #     gainCor = 0.9*gain_2nd
            # if gain2calcu > 0.95*gain_2nd:
            fndUp = GBW * 3.2
            fndDown = GBW * 2.5

            debug(fndDown, fndCalcu, fndUp, l2)
            if fndDown < fndCalcu and fndCalcu < fndUp:
                M4.l = l2
                M4.vgs = self.vdd / 2 - N_vds
                flag2 = 0
                break
            elif fndCalcu > fndUp and l2 >= M1.l:
                M4.l = M1.l
                M4.vgs = self.vdd / 2 - N_vds
                break
            else:
                M4.vgs = self.vdd / 2 - N_vds
                M4.l = self.lmin
                
        # if M4.l == self.lmin:
        #     M4.l = M4.l*1.5
        M4.l = round(M4.l, 2)
        if M4.l == 0:
            raise Exception("带宽无法满足要求!")
        
        if M4.vgs == 0:
            for v5 in np.arange(
                self.vdd / 2 - N_vds, self.vdd / 2 * 1.16 - N_vds, 0.01
            ):
                v5 = v5 - 0.05
                
                M4.idOverW = (
                    lookup(
                         method="comb", model="nch", outpar="ID", VGS=v5, VBS=-M4.vbs, VDS=M4.vds, L=M4.l
                    )
                    / 5
                )
                M4.w = M4.id / M4.idOverW
                debug("new calcu M4 :", M4.vgs, M4.w, M4.id, M4.idOverW)
                M4.cgs = (
                    lookup(
                         method="comb", model="nch", outpar="CGS", VGS=v5, VBS=-M4.vbs, VDS=M4.vds, L=M4.l
                    )
                    / 5
                    * M4.w
                )
                M4.cgd = (
                    lookup(
                         method="comb", model="nch", outpar="CGD", VGS=v5, VBS=-M4.vbs, VDS=M4.vds, L=M4.l
                    )
                    / 5
                    * M4.w
                )
                M4.gm = (
                    lookup(
                         method="comb", model="nch", outpar="GM", VGS=v5, VBS=-M4.vbs, VDS=M4.vds, L=M4.l
                    )
                    / 5
                    * M4.w
                )
                debug(M4.gm)
                C1 = M4.cgs + M4.cgs * gain2calcu + C_cmfb1
                Cmtp = C1 * C2 * C3
                Gmmtp = M2.gm * M4.gm * (1 / self._NGB_Rin)
                fndCalcu = (2 * Gmmtp / Cmtp) ** (1 / 3) / (2 * math.pi)
                if fndCalcu > GBW * 2.5:
                    M4.vgs = v5 + 0.05
                    # break
                debug(fndCalcu)
            if M4.vgs == 0:
                raise Exception("带宽指标无法达标!")
        if self.pdk in ["t40"]:
            M4.l=M4.l+4*self.lmin
        M4.idOverW = (
                    lookup(
                         method="comb", model="nch", outpar="ID", VGS=M4.vgs, VBS=-M4.vbs, VDS=M4.vds, L=M4.l
                    )
                    / 5
                )
        M4.w = M4.id / M4.idOverW  
        debug("M4 par is:", M4.vgs, M4.vds, M4.vbs)

        M4.m = math.ceil(M4.w / 4 / (self.P_unitm / divide))
        M4.m = M4.m * 4
        M4.w = round(M4.w / M4.m, 2)
        self.secondStageAmp = [M4.w * 1e-6, M4.l * 1e-6, M4.m, second_multi]
        debug("VGS is", M1.vgs, M4.vgs)
        # for t0 in [0.9, 0.8, 0.7, 0.6, 0.5, 0.4]:
        #     t1 = lookup( method="comb", model="nch", "ID", VGS = t0 , VBS = -M4.vbs, VDS = M4.vds, L = l2)/5
        #     t2 = M4.id / t1
        #     t3 = lookup( method="comb", model="nch", "CGS", VGS =  t0, VBS = -M4.vbs, VDS = M4.vds, L = l2)/5*t2
        #     debug(t3)
        debug("M2 and M3 vgs is :", M2.vgs, M3.vgs)
        """cmfb_1st"""
        debug(self.pdk, self.lmin)
        M5 = MOSpara()  # 输入管
        if flag2 == 0:
            vcm1 = self.vdd / 2
        else:
            vcm1 = M4.vgs + N_vds
        M5.vgs = self.vdd - vcm1 - P_vds
        M5.vds = self.vdd / 2 - N_vds - P_vds
        M5.vbs = P_vds
        M5.l = 1 * self.lmin
        if GBW < 50e6:
            M5.l = 3 * self.lmin
        M5.l = round(M5.l, 2)
        cmfb1_multi = 0
        debug("current is:", first_multi)
        for i in np.arange(math.floor(first_multi/3/2)*2, round(first_multi*1), 2):
            M5.id = i / self.bias_multi * Iref
            M5.idOverW = (
                 lookup(
                      method="comb", model="pch", outpar="ID", VGS=M5.vgs, VBS=-M5.vbs, VDS=M5.vds, L=M5.l
                )
                / 5
            )
            M5.w = M5.id / M5.idOverW
            M5.gm = (
                 lookup(
                      method="comb", model="pch", outpar="GM", VGS=M5.vgs, VBS=-M5.vbs, VDS=M5.vds, L=M5.l
                )
                / 5
                * M5.w
            )
            cmfb1_fnd = (
                Ngm1
                * i
                * 2
                / self.bias_multi
                / (2 * math.pi * Ncgs * (2 * first_multi + i * 2) / self.bias_multi)
            )
            cmfb1_gbw = M5.gm / (2 * math.pi * C1 * 2)
            debug(cmfb1_fnd, cmfb1_gbw, M5.gm, i)
            if cmfb1_fnd > cmfb1_gbw*0.1 :
                cmfb1_multi = i
                break
        if cmfb1_multi == 0:
            raise Exception("error！")

        M5.cgs = (
             lookup(  method="comb", model="pch", outpar="CGS", VGS=M5.vgs, VBS=-M5.vbs, VDS=M5.vds, L=M5.l)
            / 5
            * M5.w
        )
        debug(M5.cgs)
        if M5.cgs > C_cmfb1:
            raise Exception("error!")
        
        debug("Here is unit", M5.w, self.P_unitm, divide)
        M5.m = math.floor(M5.w / 4 / (self.P_unitm / divide))
        if M5.m == 0:
            M5.m = 1
        debug(M5.m)
        M5.m = M5.m * 4
        M5.w = round(M5.w / M5.m, 2)
        if M5.w >8:
            M5.m=M5.m*2
            M5.w = round(M5.w/2, 2)
        
        if self.pdk in ["s180mm", "s180bcd", "sharp180", "t180"]:
            self.CMFB_1st = [M5.w * 2e-6, M5.l * 1e-6, M5.m*1, cmfb1_multi]
        else:
            self.CMFB_1st = [M5.w * 1e-6, M5.l * 1e-6, M5.m, cmfb1_multi]

        """cmfb_2st"""
        M6 = MOSpara()
        vcm2 = self.vdd / 2
        M6.vgs = self.vdd - vcm2 - P_vds 
        M6.vds = self.vdd / 2 - N_vds - P_vds
        M6.vbs = P_vds
        M6.l = round(self.lmin, 2)
        cmfb2_multi = 0
        for i1 in np.arange(math.floor(second_multi/3/2)*2, round(second_multi*1), 2):
            M6.id = i1 / self.bias_multi * Iref
            M6.idOverW = (
                 lookup(
                      method="comb", model="pch", outpar="ID", VGS=M6.vgs, VBS=-M6.vbs, VDS=M6.vds, L=M6.l
                )
                / 5
            )
            M6.w = M6.id / M6.idOverW
            M6.gm = (
                 lookup(
                      method="comb", model="pch", outpar="GM", VGS=M6.vgs, VBS=-M6.vbs, VDS=M6.vds, L=M6.l
                )
                / 5
                * M6.w
            )
            M6.cgs = (
                 lookup(
                      method="comb", model="pch", outpar="CGS", VGS=M6.vgs, VBS=-M6.vbs, VDS=M6.vds, L=M6.l
                )
                / 5
                * M6.w
            )
            if M6.cgs > 0.5e-12:
                C2 = C2 - 0.5e-12 + M6.cgs
                debug(C2)
            debug(Ngm1, i1, self.bias_multi, Ncgs, second_multi, self.bias_multi)
            cmfb2_fnd = (
                Ngm1
                * i1
                * 2
                / self.bias_multi
                / (2 * math.pi * Ncgs * (second_multi + i1 * 2) / self.bias_multi)
            )
            cmfb2_gbw = M6.gm / (2 * math.pi * C2 * 2)

            debug(cmfb2_fnd, cmfb2_gbw, i1)
            if cmfb2_fnd > 0.11 * cmfb2_gbw:
                cmfb2_multi = i1
                break
        if cmfb2_multi == 0:
            raise Exception("error！")
        M6.cgs = (
             lookup(  method="comb", model="pch", outpar="CGS", VGS=M6.vgs, VBS=-M6.vbs, VDS=M6.vds, L=M6.l)
            / 5
            * M6.w
        )
        debug(M6.cgs)
        if M6.cgs - 0.8e-12 > C2 * 0.2:
            raise Exception("error!")
        
        M6.m = math.floor(M6.w / 4 / M1.w)
        if M6.m == 0:
            M6.m = 1
        M6.m = M6.m * 4
        if self.pdk in["t40"]:
            M6.m=M6.m*3
        M6.w = round(M6.w / M6.m, 2)
        if M6.w > 8:
            M6.m = M6.m*2
            M6.w = M6.w/2
            
            
        self.CMFB_2nd = [M6.w * 1e-6, M6.l * 1e-6, M6.m, cmfb2_multi]
        debug(vcm1, vcm2)
        
        self.CMFBO = self.CMFBOsizing(vcm1, self.vdd /2 -0.1, Iref)
        debug("寄生电容为：", M4.cgd)


    #电流大小为UnitIref*2
    def CMFBOsizing(self, Vref1, Vref2, Iref): 
        M1 = MOSpara()
        multi = 2
        M1.id = Iref / self.bias_multi*multi
        M1.l = 2
        
        if self.pdk in ["s180mm", "s180bcd", "sharp180", "t180"]:
            multi = 1
            M1.id = Iref / self.bias_multi*multi
            M1.l = 5
            
        M1.vgs = Vref1
        M1.idOverW = (
            lookup( method="comb", model="nch", outpar="ID", VGS=M1.vgs, VBS=0, VDS=M1.vgs, L=M1.l) / 5
        )
        M1.w = M1.id / M1.idOverW
        M1.m = 1
        M1.w = round(M1.w/M1.m, 2)
        

        # M3 = MOSpara()
        # M3.id = M1.id
        # M3.l = M1.l/2
        # M3.vgs = Vref1/2
        # M3.idOverW = (
        #     lookup( method="comb", model="nch", outpar="ID", VGS=M3.vgs, VBS=M1.vgs, VDS=M1.vgs, L=M3.l) / 5
        # )
        # M3.w = M3.id / M3.idOverW
        # M3.m = 1
        # M3.w = round(M3.w/M3.m, 2)
        

        if Vref1 == Vref2:
            
            return [
                [M1.w * 1e-6, M1.w * 1e-6],
                [M1.l * 1e-6, M1.l * 1e-6],
                [M1.m, M1.m],
                [multi],
            ]
        else:
            
            M2 = MOSpara()
            M2.id = Iref/self.bias_multi*multi
            M2.l = M1.l
            M2.vgs = Vref2
            M2.idOverW = (
                lookup( method="comb", model="nch", outpar="ID", VGS=M2.vgs, VBS=0, VDS=M2.vgs, L=M2.l) / 5
            )

            M2.w = M2.id / M2.idOverW
            M2.m = 1
            if self.pdk in ["t65"]:
                M2.m = 3
            M2.w = round(M2.w/M2.m, 2)

            # M4 = MOSpara()
            # M4.id = M2.id
            # M4.l = M2.l/2
            # M4.vgs = Vref2/2
            # M4.idOverW = (
            #     lookup( method="comb", model="nch", outpar="ID", VGS=M4.vgs, VBS=M4.vgs, VDS=M4.vgs, L=M4.l) / 5
            # )
            # M4.w = M4.id / M4.idOverW
            # M4.m = 4
            # M4.w = round(M4.w/M4.m, 2)
            
            # M2.m = 4
            # M2.w = round(M2.w/M2.m, 2)
            # return [
            #     [M1.w * 1e-6, M3.w * 1e-6, M2.w * 1e-6, M4.w * 1e-6],
            #     [M1.l * 1e-6, M3.l * 1e-6, M2.l * 1e-6, M4.l * 1e-6],
            #     [M1.m, M3.m, M2.m, M4.m],
            #     [multi],
            # ]
            return [
                [M1.w * 1e-6, M2.w * 1e-6],
                [M1.l * 1e-6, M2.l * 1e-6],
                [M1.m, M2.m],
                [multi],
            ]

    def NbiasSizing(self, Iref: float, Vdsat: float, Length: float):
        # 对象初始化
        M0 = MOSpara()  # 电流镜下
        M1 = MOSpara()  # 电流镜上
        M2 = MOSpara()  # 偏置上
        M3 = MOSpara()  # 偏置下

        M0.id = M1.id = M2.id = M3.id = Iref
        V_margin = 0.025
        if self.pdk in ["t40"]:
            V_margin = 0.06
        elif self.pdk in ["t65"]:
            V_margin = 0.05
        M0.l = M1.l = Length

        """通过vdsat设计电流镜，感觉不太靠谱"""
        # M0.vdsat = Vdsat - V_margin
        # vgsList = np.arange(0.35, 0.9, 0.01)
        # for v1 in vgsList:
        #     vdsat0 = lookup( method="comb", model="nch", outpar="VDSAT", VGS=v1, VBS=0, VDS=Vdsat, L=M0.l)
        #     # debug(vdsat0, M0.vdsat, v1)
        #     if M0.vdsat - 0.005 < vdsat0 and vdsat0 < M0.vdsat + 0.005:
        #         M0.vgs = v1
        #         break
        # if M0.vgs == 0:
        #     raise Exception("error!")

        """通过gmid设计电流镜，gmid取值随工艺稍作变化"""
        M0.gmid = 15
        vgsList = np.arange(0.35, 0.9, 0.01)
        for v1 in vgsList:
            gmid0 = lookup( method="comb", model="nch", outpar="GMOVERID", VGS=v1, VBS=0, VDS=Vdsat, L=M0.l)
            # debug(vdsat0, M0.vdsat, v1)
            if M0.gmid - 0.5 < gmid0 and gmid0 < M0.gmid + 0.5:
                M0.vgs = v1
                break
        if M0.vgs == 0:
            raise Exception("error!")
        
        debug("N电流镜的Vgs为：", M0.vgs, lookup( method="comb", model="nch", outpar="GMOVERID", VGS=M0.vgs, VBS=0, VDS=Vdsat, L=M0.l))

        global N_vgs
        N_vgs = M0.vgs
        M0.idOverW = lookup( method="comb", model="nch", outpar="ID", VGS=M0.vgs, VBS=0, VDS=Vdsat, L=M0.l)
        M0.idOverW = M0.idOverW / 5
        M0.w = M0.id / M0.idOverW

        M1.l = M0.l
        M1.gmid = 17  # 待定
        if self.pdk in ["s180mm", "s180bcd", "sharp180"]:
            M1.gmid = 15
        M1.vds = M0.vgs - Vdsat
        for v2 in vgsList:
            gmid1 = lookup(
                 method="comb", model="nch", outpar="GMOVERID", VGS=v2, VBS=-Vdsat, VDS=M1.vds, L=M1.l
            )
            if M1.gmid - 0.5 < gmid1 and gmid1 < M1.gmid + 0.5:
                M1.vgs = v2
                break
        if M1.vgs == 0:
            raise Exception("error!")

        # Vth1=lookup( method="comb", model="nch", "VT", VGS=M1.vgs, VBS=-Vdsat, VDS=M1.vds, L=M1.l)
        # Vov1=M1.vgs-Vth1
        Vov0 = Vdsat
        M1.idOverW = lookup(
             method="comb", model="nch", outpar="ID", VGS=M1.vgs, VBS=-Vdsat, VDS=M1.vds, L=M1.l
        )
        M1.idOverW = M1.idOverW / 5
        M1.w = M1.id / M1.idOverW
        M0.vds = Vdsat
        VbiasN = M0.vds + M1.vgs

        M2.l = M1.l

        M3.l = 6 * M1.l
        if self.pdk in ["t40"]:
            M3.l = 8 * M1.l
        if M3.l > 2:
            M3.l = 3 * M1.l
        
        VbiasN = VbiasN - 0.025  # 本次设计采用的w/3L的结构，在之后转化成w/L的结构会有误差
        M3.vgs = VbiasN
        M3.vds = Vov0  # 根据gmid假设的过驱动电压，这个值就是最终的实际值，是计算值的一个估计
        M2.vgs = VbiasN - M3.vds
        # debug(M2.vgs, M3.vds, M2.l)
        M2.idOverW =  lookup(
             method="comb", model="nch", outpar="ID", VGS=M2.vgs, VBS=-M3.vds, VDS=M2.vgs, L=M2.l
        )
        M2.idOverW = M2.idOverW / 5
        M2.w = M2.id / M2.idOverW

        debug(M3.l, M1.l, M3.vgs, M3.vds)
        M3.idOverW = lookup( method="comb", model="nch", outpar="ID", VGS=M3.vgs, VBS=0, VDS=M3.vds, L=M3.l)
        M3.idOverW = M3.idOverW / 5
        M3.w = M2.id / M3.idOverW

        global Ngds1, Ngm1, Ngds2, Ngm2, P_Ngds1, P_Ngm1, Ncgs, P_Nvds
        Ncgs = (
            lookup( method="comb", model="nch", outpar="CGS", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Ngds1 = (
            lookup( method="comb", model="nch", outpar="GDS", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Ngm1 = (
            lookup( method="comb", model="nch", outpar="GM", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Ngds2 = (
            lookup( method="comb", model="nch", outpar="GDS", VGS=M1.vgs, VBS=-M0.vds, VDS=M1.vds, L=M1.l)
            / 5
            * M1.w
        )
        Ngm2 = (
            lookup( method="comb", model="nch", outpar="GM", VGS=M1.vgs, VBS=-M0.vds, VDS=M1.vds, L=M1.l)
            / 5
            * M1.w
        )
        # debug(lookup( "nch","GDS", VGS=M0.vgs,VBS=0,VDS=[M0.vds-0.015, M0.vds-0.01,M0.vds-0.005,M0.vds, M0.vds+0.005, M0.vds+0.01],L=M0.l) / 5 * M0.w )
        # debug(lookup( "nch","VDSAT",VGS=M0.vgs,VBS=0,VDS=M0.vds,L=M0.l) )

        for vgsSump in np.arange(1, 0.3, -0.01):
            M0_vds = vgsSump
            if M0_vds > 1:
                M0_vds = 1
            M0_ide = (
                lookup( method="comb", model="nch", outpar="ID", VGS=vgsSump, VBS=0, VDS=M0_vds, L=M0.l) / 5
            )
            if M0_ide <= M0.idOverW * 1 / 2:
                vgs0 = vgsSump
                break
            elif vgsSump < 0.32:
                raise Exception("error")

        P_Nvds = lookup( method="comb", model="nch", outpar="VDSAT", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
        P_Ngds1 = (
            lookup( method="comb", model="nch", outpar="GDS", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
            / 5
            * M0.w
            * 2
        )
        P_Ngm1 = (
            lookup( method="comb", model="nch", outpar="GM", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
            / 5
            * M0.w
            * 2
        )
        debug(M1.vgs, M0.vgs, M2.vgs, M3.vgs)
        self.N_unitm = M0.w / self.bias_multi
        M0.m = self.bias_multi
        debug(type(self.N_unitm))
        M0.w = round(self.N_unitm, 2)
        M1.m = M0.m
        M1.w = round(M1.w / M1.m, 2)
        # if self.pdk in ["s180bcd", "sharp180"]:
        #     M2.m = M1.m * 2
        # else:
        #     M2.m = M1.m * 1
        if self.pdk in ["t65", "t40"]:
            M2.m = int(M1.m*2)
            M3.m = int(M1.m/2)
        else:
            M2.m = int(M1.m/2)
            M3.m = int(M1.m/2)
        
        M2.w = round(M2.w / M2.m, 2)
        M3.w = round(M3.w / M3.m, 2)
        return [
            [M1.w * 1e-6, M0.w * 1e-6, M2.w * 1e-6, M3.w * 1e-6],
            [M1.l * 1e-6, M0.l * 1e-6, M2.l * 1e-6, round(M3.l / 3, 2) * 1e-6],
            [M1.m, M0.m, M2.m, M3.m],
        ]

    def PbiasSizing(self, Iref: float, Vdsat: float, Length: float):
        # 对象初始化
        M0 = MOSpara()  # 电流镜下
        M1 = MOSpara()  # 电流镜上
        M2 = MOSpara()  # 偏置上
        M3 = MOSpara()  # 偏置下

        M0.id = M1.id = M2.id = M3.id = Iref
        V_margin = 0.025
        M0.l = M1.l = Length

        """以vdsat来设计电流镜"""
        # M0.vdsat = Vdsat - V_margin
        # vgsList = np.arange(0.35, 0.9, 0.01)
        # for v1 in vgsList:
        #     vdsat0 =  lookup(  method="comb", model="pch", outpar="VDSAT", VGS=v1, VBS=0, VDS=Vdsat, L=M0.l)
        #     # debug(vdsat0, M0.vdsat, v1)
        #     if M0.vdsat - 0.005 < vdsat0 and vdsat0 < M0.vdsat + 0.005:
        #         M0.vgs = v1
        #         break
        # if M0.vgs == 0:
        #     raise Exception("error!")
        
        """通过gmid设计电流镜，gmid取值随工艺稍作变化"""
        M0.gmid = 15
        vgsList = np.arange(0.35, 0.9, 0.01)
        for v1 in vgsList:
            gmid0 = lookup( method="comb", model="pch", outpar="GMOVERID", VGS=v1, VBS=0, VDS=Vdsat, L=M0.l)
            # debug(vdsat0, M0.vdsat, v1)
            if M0.gmid - 0.5 < gmid0 and gmid0 < M0.gmid + 0.5:
                M0.vgs = v1
                break
        if M0.vgs == 0:
            raise Exception("error!")

        global P_vgs
        P_vgs = M0.vgs
        M0.idOverW =  lookup(  method="comb", model="pch", outpar="ID", VGS=M0.vgs, VBS=0, VDS=Vdsat, L=M0.l)
        M0.idOverW = M0.idOverW / 5
        M0.w = M0.id / M0.idOverW

        M1.l = M0.l
        M1.gmid = 17  # 待定
        if self.pdk in ["s180mm", "s180bcd", "sharp180"]:
            M1.gmid = 10
        elif self.pdk in ["t40"]:
            M1.gmid = 15
        M1.vds = M0.vgs - Vdsat
        for v2 in vgsList:
            gmid1 =  lookup(
                  method="comb", model="pch", outpar="GMOVERID", VGS=v2, VBS=-Vdsat, VDS=M1.vds, L=M1.l
            )
            if M1.gmid - 0.5 < gmid1 and gmid1 < M1.gmid + 0.5:
                M1.vgs = v2
                break
        if M1.vgs == 0:
            raise Exception("error!")

        # Vth1=lookup(  method="comb", model="pch", "VT", VGS=M1.vgs, VBS=-Vdsat, VDS=M1.vds, L=M1.l)
        # Vov1=M1.vgs-Vth1
        Vov0 = Vdsat
        M1.idOverW =  lookup(
              method="comb", model="pch", outpar="ID", VGS=M1.vgs, VBS=-Vdsat, VDS=M1.vds, L=M1.l
        )
        M1.idOverW = M1.idOverW / 5
        M1.w = M1.id / M1.idOverW
        M0.vds = Vdsat
        VbiasP = M0.vds + M1.vgs

        M2.l = M1.l
        M3.l = 3 * M1.l
        debug(M0.vgs, VbiasP, M1.vgs, Vdsat, M1.vds)
        VbiasP = VbiasP - 0.025  # 本次设计采用的w/3L的结构，在之后转化成w/L的结构会有误差
        M3.vgs = VbiasP
        M3.vds = Vov0  # 根据gmid假设的过驱动电压，这个值就是最终的实际值，是计算值的一个估计
        M2.vgs = VbiasP - M3.vds
        # debug(M2.vgs,M3.vds)
        # Vth2=lookup( "nch","VT",VGS=M2.vgs,VBS=-M3.vds,VDS=M2.vgs,L=M2.l)
        # debug(Vth2)
        M2.idOverW =  lookup(
              method="comb", model="pch", outpar="ID", VGS=M2.vgs, VBS=-M3.vds, VDS=M2.vgs, L=M2.l
        )
        M2.idOverW = M2.idOverW / 5
        M2.w = M2.id / M2.idOverW

        debug("P type bias' par is:", M3.vgs, M3.vds, M3.l, N_vds, P_vds)
        M3.idOverW = lookup(  method="comb", model="pch", outpar="ID", VGS=M3.vgs, VBS=0, VDS=M3.vds, L=M3.l)
        M3.idOverW = M3.idOverW / 5
        M3.w = M2.id / M3.idOverW

        global Pgds1, Pgm1, Pgds2, Pgm2, Pcgs, N_Pgds1, N_Pgm1, N_Pvds
        Pcgs = (
            lookup(  method="comb", model="pch", outpar="CGS", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Pgds1 = (
            lookup(  method="comb", model="pch", outpar="GDS", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Pgm1 = (
            lookup(  method="comb", model="pch", outpar="GM", VGS=M0.vgs, VBS=0, VDS=M0.vds, L=M0.l)
            / 5
            * M0.w
        )
        Pgds2 = (
            lookup(  method="comb", model="pch", outpar="GDS", VGS=M1.vgs, VBS=-M0.vds, VDS=M1.vds, L=M1.l)
            / 5
            * M1.w
        )
        Pgm2 = (
            lookup(  method="comb", model="pch", outpar="GM", VGS=M1.vgs, VBS=-M0.vds, VDS=M1.vds, L=M1.l)
            / 5
            * M1.w
        )
        for vgsSump in np.arange(1, 0.3, -0.01):
            M0_vds = vgsSump
            if M0_vds > 1:
                M0_vds = 1
            M0_ide = (
                lookup(  method="comb", model="pch", outpar="ID", VGS=vgsSump, VBS=0, VDS=M0_vds, L=M0.l) / 5
            )
            # debug(M0_ide, M0.idOverW * 2)
            if M0_ide <= M0.idOverW * 1 / 2:
                vgs0 = vgsSump
                break
            elif vgsSump < 0.32:
                raise Exception("error")
        N_Pvds = lookup(  method="comb", model="pch", outpar="VDSAT", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
        N_Pgds1 = (
            lookup(  method="comb", model="pch", outpar="GDS", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
            / 5
            * M0.w
            * 2
        )
        N_Pgm1 = (
            lookup(  method="comb", model="pch", outpar="GM", VGS=vgs0, VBS=0, VDS=vgs0, L=M0.l)
            / 5
            * M0.w
            * 2
        )
        debug(
            "就是这里：",
            M1.vgs,
            M0.vgs,
            M2.vgs,
            M3.vgs,
             lookup(  method="comb", model="pch", outpar="VT", VGS=M1.vgs, VBS=-Vdsat, VDS=M1.vds, L=M1.l),
        )
        M0.m = M1.m = self.bias_multi
        self.P_unitm = M0.w / self.bias_multi
        M0.w = round(self.P_unitm, 2)
        while M0.w > 17:
            M0.w = round(M0.w/2, 2)
            M0.m = M1.m = M0.m*2
        self.P_unitm = M0.w
        if self.P_unitm < 2:
            self.P_unitm = 2
        M1.w = round(M1.w / M1.m, 2)
        
        
        if self.pdk in ["t65"]:
            M2.m = M1.m*2
            M3.m = M1.m
        else:
            M2.m = M1.m
            M3.m = int(M1.m/2)
        
        M2.w = round(M2.w / M2.m, 2)
        
        M3.w = round(M3.w / M3.m, 2)
        return [
            [M1.w * 1e-6, M0.w * 1e-6, M2.w * 1e-6, M3.w * 1e-6],
            [M1.l * 1e-6, M0.l * 1e-6, M2.l * 1e-6, M3.l / 3 * 1e-6],
            [M1.m, M0.m, M2.m, M3.m],
        ]

    def gainCalcu(
        self, ro1, gm1, ro2, gm2, ro3, gm3, multi
    ):  # 123管分别为输入管，n cascode管，p cascode管
        debug(multi, 1 / Pgds1, 1 / Ngds1)
        multi = multi / self.bias_multi
        debug(multi, 1 / (Pgds1 * multi), 1 / (Ngds1 * multi))
        MOS = MOSpara()
        k = (1 / (Pgds1 * multi)) / (self._PGB_Rin + 1 / (Pgds1 * multi))
        m = MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi)) / (
            MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi)) + self._NGB_Rin
        )
        Rp = ro3 * (1 + gm3 * (k * self._PGB_Rf + (1 - k) * (1 / (Pgds1 * multi)))) + (
            1 - k
        ) * (1 / (Pgds1 * multi))
        Rn = ro2 * (
            1
            + gm2
            * (
                m * self._NGB_Rf
                + (1 - m) * MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi))
            )
        ) + (1 - m) * (MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi)))
        debug(Rn, Rp)
        debug(
            gm2
            * ro2
            * self._NGB_Rf
            / self._NGB_Rin
            * MOS.parallel(
                self._NGB_Rin,
                MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi)),
            )
        )
        debug(
            gm3
            * ro3
            * self._PGB_Rf
            / self._PGB_Rin
            * MOS.parallel(self._PGB_Rin, 1 / (Pgds1 * multi)),
            MOS.parallel(self._PGB_Rin, 1 / (Pgds1 * multi)),
            self._PGB_Rf,
            self._PGB_Rin,
            1 / Pgm2,
        )
        return gm1 * MOS.parallel(Rp, Rn)

    def noiseCalcu(self, ro1, gm1, ro2, gm2, ro3, gm3, multi):  # 123管分别为输入管，n管，p管
        multi = multi / self.bias_multi
        MOS = MOSpara()
        IN_noise = (
            8 / 3 * MOS.k * MOS.T * (N_Pgm1 * 1.9 + Ngm1 + Ngm2 * 2) * self.NGB_multi
        )
        IP_noise = (
            8 / 3 * MOS.k * MOS.T * (P_Ngm1 * 1.9 + Pgm1 + Pgm2 * 2) * self.PGB_multi
        )
        Rsn = MOS.parallel(ro1, 1 / (Ngds1 * multi), 1 / (Ngds1 * multi))
        Rsp = 1 / (Pgds1 * multi)
        GBN_nosie = (
            IN_noise
            * self._NGB_Rf
            * gm2
            / (
                (
                    1
                    + gm2 * MOS.parallel(self._NGB_Rin, Rsn, ro2)
                    + gm2
                    * self._NGB_Rf
                    * MOS.parallel(Rsn, ro2)
                    / (MOS.parallel(Rsn, ro2) + self._NGB_Rin)
                )
                * (MOS.parallel(Rsn, self._NGB_Rin) + ro2)
                / ro2
            )
        )
        GBP_nosie = (
            IP_noise
            * self._PGB_Rf
            * gm3
            / (
                (
                    1
                    + gm3 * MOS.parallel(self._PGB_Rin, Rsp, ro3)
                    + gm3
                    * self._PGB_Rf
                    * MOS.parallel(Rsp, ro3)
                    / (MOS.parallel(Rsp, ro3) + self._PGB_Rin)
                )
                * (MOS.parallel(Rsp, self._PGB_Rin) + ro3)
                / ro3
            )
        )
        vin_noise = (
            8 / 3 * MOS.k * MOS.T * (gm1 + 2 * Ngm1 * multi + Pgm1 * multi)
            + GBN_nosie
            + GBP_nosie
        ) / (gm1 * gm1)
        return vin_noise

    def NgainboostorSizing(self, GBW, Cload):  # 输出电流复制比

        # Cc = 100*Cload
        # if Cc<1.5e-12:
        Cc = 2.5e-12
        # if self.pdk in ["s180mm","s180bcd","sharp180"]:
        #     Cc = 3.5e-12
        flag = 0
        MOS = MOSpara()
        k = 0
        for multi in np.arange(math.ceil(first_multi/4), first_multi * 6, 2):
            k = multi / self.bias_multi
            self._NGB_Rin = MOS.parallel(
                1 / (Ngds1 * k),
                (
                    (
                        MOS.parallel(1 / (N_Pgds1 * k * 2), 1 / (N_Pgm1 * k * 2))
                        + 1 / (Ngds2 * k)
                    )
                    / (1 + Ngm2 / Ngds2)
                ),
            )
            self._NGB_Rf = MOS.parallel(1 / (N_Pgds1 * k), Ngm2 / (Ngds2 * Ngds1 * k))
            # Cc = Cload * self._NGB_Rf/self._NGB_Rin
            GBWcalcu = 1 / (2 * math.pi * self._NGB_Rin * Cc)
            # debug(self._NGB_Rf/self._NGB_Rin,GBWcalcu)
            if GBWcalcu > 1 * GBW:
                flag = 1
                break
        if flag == 0:
            raise Exception("error!")
        self.NGB_multi = k
        debug(self._NGB_Rin, self._NGB_Rf)
        return Cc

    def PgainboostorSizing(self, GBW, Cload):  # 输出电流复制比

        # Cc = 100*Cload
        # if Cc<1.5e-12:
        Cc = 2e-12
        # if self.pdk in ["s180mm","s180bcd","sharp180"]:
        #     Cc = 3e-12
        flag = 0
        MOS = MOSpara()
        k = 0
        for multi in np.arange(math.ceil(first_multi/4), first_multi * 6, 2):
            k = multi / self.bias_multi
            debug(
                "计算：",
                MOS.parallel(1 / (P_Ngds1 * k * 2), 1 / (P_Ngm1 * k * 2)),
                1 / (Pgds2 * k),
                Pgm2 / Pgds2,
            )
            debug(1 / P_Ngds1, 1 / Ngds1)
            self._PGB_Rin = MOS.parallel(
                1 / (Pgds1 * k),
                (
                    (
                        MOS.parallel(1 / (P_Ngds1 * k * 2), 1 / (P_Ngm1 * k * 2))
                        + 1 / (Pgds2 * k)
                    )
                    / (1 + Pgm2 / Pgds2)
                ),
            )
            self._PGB_Rf = MOS.parallel(1 / (P_Ngds1 * k), Pgm2 / (Pgds2 * Pgds1 * k))
            debug(1 / (P_Ngds1 * k), Pgm2 / Pgds2, 1 / (Pgds1 * k))
            # Cc = Cload * self._PGB_Rf/self._PGB_Rin

            GBWcalcu = 1 / (2 * math.pi * self._PGB_Rin * Cc)
            # debug(self._PGB_Rf/self._PGB_Rin,GBWcalcu)
            if GBWcalcu > 1 * GBW:
                flag = 1
                break
        if flag == 0:
            Exception("error!")
            # self.PGB_gain = self._PGB_Rf / self._PGB_Rin
        self.PGB_multi = k
        debug(self._PGB_Rin, self._PGB_Rf)
        return Cc

    def show(self):
        debug("N型偏置：", self.Nbias)
        debug("P型偏置：", self.Pbias)
        debug("第一级电路：", self.firstStageAmp)
        debug("第二级电路：", self.secondStageAmp)
        debug("第一级共模电路：", self.CMFB_1st)
        debug("第二级共模电路：", self.CMFB_2nd)
        debug("GBN:", self.GBN_Cc, self.NGB_multi)
        debug("GBP", self.GBP_Cc, self.PGB_multi)
        debug("Cc：", self.Cc_cascode)
        debug("共模偏置：", self.CMFBO)
